﻿package org.openChart.display 
{
	import flash.display.FrameLabel;
	import flash.display.InterpolationMethod;
	import flash.geom.Point;
	import org.openChart.display.chart.DisplayBarElement;
	import org.openChart.display.chart.DisplayPieElement;
	import org.openChart.meta.data.DataElement;
	import org.openChart.meta.data.DataGroup;
	import org.openChart.meta.data.GroupSet;
	import org.openChart.meta.ChartType;
	import org.openChart.meta.Axis;
	import org.openChart.util.Rectangle;
	
	/**
	 * ...
	 * @author Chongyuan
	 */
	public class DisplayGroupSet extends DisplayBaseObject implements DisplayInterface
	{
		private var groups_:Array = new Array();
		//private var groupSet_:GroupSet;
		private var parent_:DisplayChart;
		
		private var maxValue_:Number = Number.MIN_VALUE;
		private var minValue_:Number = Number.MAX_VALUE;
		private var maxTotal_:Number = Number.MIN_VALUE;
		private var length_:Number = 0;
		
		private const max_element_width:Number = 30;
		
		public function DisplayGroupSet(groupSet:GroupSet, parent_:DisplayChart) 
		{
			//this.groupSet_ = groupSet;
			this.parent_ = parent_;
			super(groupSet);
		}
		
		public override function resize(rectangle:Rectangle):void
		{
			var chartType:String = parent.chartType;
			if (chartType == ChartType.CUMULATE_BAR_CHART_2D 
				|| chartType == ChartType.CUMULATE_BAR_CHART_3D_CUBE
				|| chartType == ChartType.CUMULATE_BAR_CHART_3D_CYLINDER
				|| chartType == ChartType.CUMULATE_LINE_CHART)
			{
				this.initCumulateBar2d();
			}
			else if (chartType == ChartType.DRUSY_BAR_CHART_2D
				|| chartType == ChartType.DRUSY_BAR_CHART_3D_CONE
				|| chartType == ChartType.DRUSY_BAR_CHART_3D_CUBE
				|| chartType == ChartType.DRUSY_BAR_CHART_3D_CYLINDER
				|| chartType == ChartType.DRUSY_BAR_CHART_3D_PYRAMID
				|| chartType == ChartType.DRUSY_LINE_CHART)
			{
				this.initDrusyBar2d();
			}
			else if (chartType == ChartType.PERCENT_BAR_CHART_2D
				|| chartType == ChartType.PERCENT_BAR_CHART_3D_CUBE
				|| chartType == ChartType.PERCENT_BAR_CHART_3D_CYLINDER
				|| chartType == ChartType.PERCENT_LINE_CHART)
			{
				this.initPercentBar2d();
			}
			else if (chartType == ChartType.PERCENT_BAR_CHART_3D_CONE
				|| chartType == ChartType.PERCENT_BAR_CHART_3D_PYRAMID)
			{
				this.initPercentBar3d();
			}
			else if (chartType == ChartType.CUMULATE_BAR_CHART_3D_CONE
				|| chartType == ChartType.CUMULATE_BAR_CHART_3D_PYRAMID)
			{
				this.initCumulateBar3d();
			}
			else if (chartType == ChartType.PIE_CHART_2D
				|| chartType == ChartType.PIE_CHART_3D
				|| chartType == ChartType.DISCONNECTED_PIE_CHART_2D
				|| chartType == ChartType.DISCONNECTED_PIE_CHART_3D)
			{
				initPieChart();
			}
		}
		
		private function initCumulateBar2d():void
		{
			var barChart:DisplayBarChart = parent as DisplayBarChart;
			
			var labelCount:Number = barChart.xDisplayAxis.labels.length;
			var groupCount:Number = groupSet.getLength();
			var xlength:Number = Math.abs(barChart.xDisplayAxis.endPoint.x - barChart.xDisplayAxis.startPoint.x);
			var segment:Number = xlength / labelCount;
			var elementWidth:Number = segment / 3;
			
			var ylength:Number = Math.abs(barChart.yDisplayAxis.startPoint.y - barChart.yDisplayAxis.endPoint.y);
			var yAxis:Axis = barChart.yDisplayAxis.axis as Axis;
			var value:Number = yAxis.maxValue - yAxis.minValue;
			
			var heights:Array = new Array();
			for (var i:uint = 0; i < length; i++)
			{	
				
				var displayGroup:DisplayGroup = getAt(i);
				for ( var j:uint = 0; j < displayGroup.length ; j++ )
				{
					if (heights.length <= j)
					{
						heights.push(0);
					}
					
					var displayElement:DisplayBarElement = displayGroup.getAt(j) as DisplayBarElement;
					displayElement.height = ylength / value * displayElement.value;
					displayElement.width = elementWidth;
					displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + segment / 2;
					displayElement.position.y = barChart.xDisplayAxis.startPoint.y - heights[j - 1];
					heights[j - 1] += displayElement.height;
				}
			}
		}
		
		private function initPercentBar2d():void
		{
			var barChart:DisplayBarChart = parent as DisplayBarChart;
			
			var labelCount:Number = barChart.xDisplayAxis.labels.length;
			var xlength:Number = Math.abs(barChart.xDisplayAxis.endPoint.x - barChart.xDisplayAxis.startPoint.x);
			var segment:Number = xlength / labelCount;
			var elementWidth:Number = segment / 3;
			if (elementWidth > this.max_element_width)
			{
				elementWidth = max_element_width;
			}
			
			var ylength:Number = Math.abs(barChart.yDisplayAxis.startPoint.y - barChart.yDisplayAxis.endPoint.y);
			var yAxis:Axis = barChart.yDisplayAxis.axis as Axis;
			
			var heights:Array = new Array();
			
			for (var i:uint = 0; i < length_; i++)
			{	
				var displayGroup:DisplayGroup = getAt(i);
				for ( var j:uint = 0; j < displayGroup.length; j ++)
				{
					if (heights.length <= j)
					{
						heights.push(0);
					}
					
					var displayElement:DisplayBarElement = displayGroup.getAt(j) as DisplayBarElement;
					
					displayElement.height = ylength * (displayElement.value / groupSet.getTotalValues()[j]);
					displayElement.width = elementWidth;
					displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + segment / 2;
					displayElement.position.y = barChart.xDisplayAxis.startPoint.y - heights[j];
					heights[j] += displayElement.height;
				}
			}
		}
		
		private function initDrusyBar2d():void
		{
			var barChart:DisplayBarChart = parent as DisplayBarChart;
			
			var labelCount:Number = barChart.xDisplayAxis.labels.length;
			var xlength:Number = Math.abs(barChart.xDisplayAxis.endPoint.x - barChart.xDisplayAxis.startPoint.x);
			var segment:Number = xlength / labelCount;
			var elementWidth:Number = segment / (length + 2);
			if (elementWidth > this.max_element_width)
			{
				elementWidth = max_element_width;
			}
			
			var ylength:Number = Math.abs(barChart.yDisplayAxis.startPoint.y - barChart.yDisplayAxis.endPoint.y);
			var yAxis:Axis = barChart.yDisplayAxis.axis as Axis;
			var value:Number = yAxis.maxValue - yAxis.minValue;
			
			for (var i:uint = 0; i < length; i++)
			{
				
				var displayGroup:DisplayGroup = getAt(i);
				for ( var j:uint = 0; j < displayGroup.length; j ++)
				{
					
					var displayElement:DisplayBarElement = displayGroup.getAt(j) as DisplayBarElement;
					displayElement.height = ylength / value * (displayElement.value - yAxis.minValue);
					displayElement.width = elementWidth;
					
					if (barChart.chartType == ChartType.DRUSY_LINE_CHART)
					{
						displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + segment / 2;
					}
					else
					{
						displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + i * elementWidth + (segment / 2 - length * elementWidth / 2);	
					}
					displayElement.position.y = barChart.xDisplayAxis.startPoint.y;
				}
			}
		}
		
		private function initCumulateBar3d():void
		{
			var barChart:DisplayBarChart = parent as DisplayBarChart;
			
			var labelCount:Number = barChart.xDisplayAxis.labels.length;
			var xlength:Number = Math.abs(barChart.xDisplayAxis.endPoint.x - barChart.xDisplayAxis.startPoint.x);
			var segment:Number = xlength / labelCount;
			var elementWidth:Number = segment / 3;
			if (elementWidth > this.max_element_width)
			{
				elementWidth = max_element_width;
			}
			
			var ylength:Number = Math.abs(barChart.yDisplayAxis.startPoint.y - barChart.yDisplayAxis.endPoint.y);
			var yAxis:Axis = barChart.yDisplayAxis.axis as Axis;
			var value:Number = yAxis.maxValue - yAxis.minValue;
			
			var heights:Array = new Array();
			var values:Array = new Array();
			
			for (var i:uint = 0; i < length; i++)
			{	
				
				var displayGroup:DisplayGroup = getAt(i);
				for ( var j:uint = 0; j < displayGroup.length; j++)
				{
					if (heights.length <= j)
					{
						heights.push(0);
					}
					if (values.length <= j)
					{
						values.push(0);
					}
					
					var displayElement:DisplayBarElement = displayGroup.getAt(j) as DisplayBarElement;
					
					displayElement.height = ylength / value * (displayElement.value * yAxis.minValue);
					displayElement.width = elementWidth * (groupSet.getTotalValues()[j] - values[j]) / groupSet.getTotalValues()[j];
					values[j] += displayElement.value;
					displayElement.topWidth = elementWidth * (groupSet.getTotalValues()[j] - values[j]) / groupSet.getTotalValues()[j];
					
					displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + segment / 2;
					displayElement.position.y = barChart.xDisplayAxis.startPoint.y - heights[j];
					
					heights[j - 1] += displayElement.height;
				}
			}
		}
		
		private function initPercentBar3d( ):void
		{
			var barChart:DisplayBarChart = parent as DisplayBarChart;
			
			var labelCount:Number = barChart.xDisplayAxis.labels.length;
			var xlength:Number = Math.abs(barChart.xDisplayAxis.endPoint.x - barChart.xDisplayAxis.startPoint.x);
			var segment:Number = xlength / labelCount;
			var elementWidth:Number = segment / 3;
			
			var ylength:Number = Math.abs(barChart.yDisplayAxis.startPoint.y - barChart.yDisplayAxis.endPoint.y);
			var yAxis:Axis = barChart.yDisplayAxis.axis as Axis;
			var value:Number = yAxis.maxValue - yAxis.minValue;
			
			var heights:Array = new Array();
			var values:Array = new Array();
			
			for (var i:uint = 0; i < length; i++)
			{	
				
				var displayGroup:DisplayGroup = getAt(i);
				for ( var j:uint = 0; j < displayGroup.length; j ++)
				{
					if (heights.length <= (j))
					{
						heights.push(0);
					}
					if (values.length <= (j))
					{
						values.push(0);
					}
					
					var displayElement:DisplayBarElement = displayGroup.getAt(j) as DisplayBarElement;
					
					displayElement.height = ylength * (displayElement.value / groupSet.getTotalValues()[j]);
					displayElement.width = elementWidth * (groupSet.getTotalValues()[j] - values[j]) / groupSet.getTotalValues()[j];
					values[j] += displayElement.value;
					displayElement.topWidth = elementWidth * (groupSet.getTotalValues()[j] - values[j]) / groupSet.getTotalValues()[j];
					
					displayElement.position.x = barChart.xDisplayAxis.startPoint.x + j * segment + segment / 2;
					displayElement.position.y = barChart.xDisplayAxis.startPoint.y - heights[j];
					
					heights[j] += displayElement.height;
				}
			}
		}
		
		private function initPieChart ():void
		{
			
			var pieChart:DisplayPieChart = parent as DisplayPieChart;
			
			var width:Number = Math.abs(pieChart.right - pieChart.left);
			var height:Number = Math.abs(pieChart.bottom - pieChart.top);
			
			var deviation:Number = pieChart.deviation;
			var thickness:Number = pieChart.thickness;
			var chartType:String = pieChart.chartType;
			
			var centerPoint:Point = new Point(width / 2 , height / 2 );
			var radius:Number = Math.min(width, height) / 2 * 0.75;
			
			for (var i:uint = 0; i < length; i++)
			{
				var displayGroup:DisplayGroup = getAt(i);
				var total:Number = displayGroup.total;
				
				var beginAngle:Number = 0;
				var offsetAngle:Number = -1;
				
				for (var j:uint = 0; j < displayGroup.length; j++)
				{
					var displayElement:DisplayPieElement = displayGroup.getAt(j) as DisplayPieElement;
					
					var endAngle:Number = 360 * displayElement.value/ total + beginAngle;
					displayElement.beginAngle = beginAngle;
					displayElement.endAngle = endAngle;
					beginAngle = endAngle;
					
					if (offsetAngle < 0)
					{
						offsetAngle = (180 - displayElement.beginAngle - displayElement.endAngle) / 2;
					}
					
					displayElement.beginAngle += offsetAngle;
					displayElement.endAngle += offsetAngle;
					displayElement.deviation = deviation;
					displayElement.longRadius = radius;
					displayElement.shotRadius = radius;
					
					var colorLabel:DisplayColorLabel = parent.parent.labels.getAt(i) as DisplayColorLabel;
					if (colorLabel)
					{
						colorLabel.color = displayElement.color;
					}
				}
				displayGroup.sortByMiddleAngle();
			}
			
		}
		
		public override function initialize():void
		{
			clear();
			var groupSet:GroupSet = this.groupSet;
			for (var i:uint = 0; i < groupSet.getLength(); i++ )
			{
				//trace(groupSet.getLength());
				var displayGroup:DisplayGroup = new DisplayGroup(groupSet.getGroup(i + 1), this);
				displayGroup.initialize();
				if (parent.chartType.indexOf("bar") > 0 || parent.chartType.indexOf("line") > 0)
				{
					var displayColorLabel:DisplayColorLabel = new DisplayColorLabel(null);
					displayColorLabel.color = displayGroup.getAt(0).color;
					
					var displayTextLabel:DisplayTextLabel = new DisplayTextLabel(null);
					displayTextLabel.text = displayGroup.groupName;
					displayTextLabel.textSize = 14;
					displayColorLabel.label = displayTextLabel;
					parent.parent.labels.addColorLabel(displayColorLabel);
				}
				
				addGroup(displayGroup);
			}
		}
		
		public function addGroup(group:DisplayGroup):void
		{
			length_++;
			groups_.push(group);
			if (maxValue_ < group.maxValue)
				maxValue_ = group.maxValue;
			if (minValue_ > group.minValue)
				minValue_ = group.minValue;
			if (maxValue_ < group.total)
				maxTotal_ = group.total;
		}
		
		public function getAt(index:uint):DisplayGroup
		{
			if (index < 0 || index >= length_)
				throw new Error("index out of boundary error!");
			return groups_[index] as DisplayGroup;
		}
		
		public function clear():void
		{
			for (var i:uint = 0; i < length_; i++ )
			{
				groups_.pop();
			}
			length_ = 0;
			maxValue_ = Number.MIN_VALUE;
			minValue_ = Number.MAX_VALUE;
		}
		
		public function get groupSet():GroupSet
		{
			return this.dataModel as GroupSet;
		}
		
		public function get parent():DisplayChart
		{
			return parent_;
		}
		
		public function get maxValue():Number
		{
			return maxValue_;
		}
		
		public function get minValue():Number
		{
			return minValue_;
		}
		
		public function get maxTotal():Number
		{
			return maxTotal_;
		}
		
		public function get length():uint
		{
			return length_;
		}
		public function toString():String
		{
			var str:String = "Object:DisplayGroupSet ";
			for (var i:uint = 0; i < length_; i++ )
			{
				str += groups_[i];
			}
			return str;
		}
	}
	
}